package quarto.test;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.InetAddress;
import java.net.Socket;
import quarto.Message;


/**
 * Klasse die de communicatie tussen de player en de UI regelt
 * @knows
 * - De Player, het Board en de ClientUI
 * @does
 * - Verbinding maken met server
 * - Input van de server doorsturen naar Player
 * - Output van de player doorsturen naar ClientHandler
 * @author Frank Borgonjen & Tim Smit
 */
public class Client extends Thread
{
    private ServerTest ui;
    private String clientName;
    private Socket sock;
    private BufferedReader in;
    private BufferedWriter out;
    
    /**
     * Construeert een Client-object en probeert een socketverbinding
     * met een Server op te starten.
     */
    public Client(String name, InetAddress host, int port, ServerTest ui) throws IOException
    {
        this.ui = ui;
        this.clientName = name;

        try
        {
            this.sock = new Socket(host, port);   
        }
        catch (IOException e)
        {
            throw new IOException(String.format(Message.CLIENT_ERROR_CONNECTING, host, port));
        }
        catch (IllegalArgumentException e)
        {
            throw new IllegalArgumentException(Message.CLIENT_ERROR_OUT_OF_RANGE);
        }
        
        // als de socket opgestart is
        if (this.sock != null)
        {
            try
            {
                this.in = new BufferedReader(new InputStreamReader(sock.getInputStream()));
                this.out = new BufferedWriter(new OutputStreamWriter(sock.getOutputStream()));
            }
            catch (IOException e)
            {
                throw new IOException(Message.CLIENT_ERROR_STREAM_INIT);
            }
        }
    }

    /**
     * Wordt aangeroepen bij het starten van de Thread.
     * In een oneindige loop wordt er gekeken of er data op de input stream
     * is komen te staan. Zodra er data opstaat moet deze geinterpreteerd
     * en uitgevoerd worden.
     */
    public void run()
    {
        String s = null;
        try
        {
            while (true)
            {
                // checken of er nog wat te lezen is.
                s = in.readLine();
                if (s != null)
                {
                    this.ui.addReaction(this, s);
                }
                else
                {
                    throw new IOException();
                }
            }
        }
        // fout, dus afsluiten
        catch (IOException e)
        {
            this.shutdown();
        }
    }
    
    /**
     * Stuurt een commando via de output stream naar de ClientHandler
     * @param msg het commando dat verstuurd wordt
     */
    public void sendMessage(String msg)
    {
        try
        {
            this.out.write(msg);
            this.out.newLine();
            this.out.flush();
        }
        catch (IOException e)
        {
            System.out.print(Message.CLIENT_ERROR_SEND_ERROR);
        }
    }
    
    /**
     * Sluit de input stream, output stream en de socket verbinding.
     * ClientHandler merkt vervolgens dat de verbinding verbroken is en geeft
     * aan de server door dat de client vertrokken is.
     */
    public void shutdown()
    {
        System.out.println(Message.CLIENT_CLOSING);
        try
        {
            this.out.close();
            this.in.close();
            this.sock.close();
        } 
        catch (IOException e)
        {
            System.out.println(Message.CLIENT_ERROR_CLOSING);
        }
    }
    
    public String getClientName()
    {
        return this.clientName;
    }
}
